/*
 * Dialogue.cpp
 *
 *  Created on: Sep 7, 2013
 *      Author: jason
 */

#include <iostream>
#include <utility>
#include "../../include/Common.hpp"
#include "../../include/GameModes/Dialogue.hpp"
#include "../../include/GameModes/TownMode/TownMode.hpp"
#include "../../include/Objects/Characters.hpp"

namespace OForce_Mode {

DialogueManager::DialogueManager() :
		currentDialogue(0),
		currentLine(0),
		coolDown(0),
		timer(0){
	mInput = OForce_Input::InputEngine::Instance();
	currentState = LINE;
}

DialogueManager::~DialogueManager() {
	currentDialogue = 0;
	for (std::unordered_map<int, Dialogue *>::iterator it = dialogueMap.begin();
			it != dialogueMap.end(); it++) {
		delete it->second;
	}
	dialogueMap.clear();
}

void DialogueManager::addDialogue(Dialogue* dialogue) {
	if (dialogue == NULL) {
		std::cerr << "Error adding dialogue\n";
		return;
	}
	if (getDialogue(dialogue->getDialogueID()) != NULL) {
		std::cerr << "Error: dialogue with ID " << dialogue->getDialogueID();
		std::cerr << " already exists.\n";
		return;
	}
	dialogueMap.insert(std::make_pair(dialogue->getDialogueID(), dialogue));
}

void DialogueManager::draw() {
//	mDialogueWindow.draw(win);
//	currentDialogue->draw();
	dialogueWindow.draw();
}

void DialogueManager::update()
{
	if (currentDialogue == NULL) {
		std::cerr << "Warning: attempted to update when there was no dialogue\n";
		return;
	}
	if (coolDown >= 0.0) {
		coolDown -= dt;
	}
	switch(currentState) {
	case LINE:
		updateLine();
		break;
	case EMOTE:
		updateEmote();
		break;
	case ACTION:
		updateAction();
		break;
	case OPTION:
		updateOption();
		break;
	}
}

void DialogueManager::updateLine()
{
//	dialogueWindow.update();
	if (coolDown <= 0.0 && (mInput->ActionState() || mInput->CancelState() ||
					mInput->MenuState())) {
		// if (!dialogueWindow.finishedTyping()) {
		//     dialogueWindow.quickly();
		// }
		// TODO if options handle them first
		// if (currentOptions != NULL) {
		//   currentState = OPTION;
		// } else {
			processDialogueEvents();
		// }
	}
	dialogueWindow.update();
}

void DialogueManager::updateEmote()
{
	// TODO
}

void DialogueManager::updateOption()
{
	// TODO
}

void DialogueManager::updateAction()
{
	// TODO
}


void DialogueManager::startDialogue(int id)
{
	Dialogue *dialogue = getDialogue(id);
	if (dialogue == NULL) {
		std::cerr << "Error getting dialogue with ID " << id << std::endl;
		return;
	}
	if (currentDialogue != NULL) {
		std::cerr << "Warning: the last dialogue was not finished.\n";
	}
	currentLine = 0;
	currentDialogue = dialogue;
	beginLine();
	TownMode::getCurrentInstance()->setState(DIALOGUE);
}

void DialogueManager::beginLine() {
	OForce_Object::Object *obj = TownMode::getCurrentInstance()->getObjectManager()->
			getObject(currentDialogue->getSpeaker(currentLine));
	if (obj == NULL) {
		std::cerr << "Error getting speaker for dialogue " <<
				currentDialogue->getDialogueID() << std::endl;
		return;
	} else if (obj->getObjectType() != OForce_Object::OBJECT_TYPE::CHARACTER_TYPE) {
		std::cerr << "Should this be talking?\n";
		std::cerr << "Object: " << currentDialogue->getSpeaker(currentLine);
		return;
	}
	OForce_Object::Character *speaker = dynamic_cast<OForce_Object::Character *> (obj);
//	if (speaker->controlledByEvent == NULL) {
		oldDir = speaker->getDirection();
		sf::Vector2f playerPos = TownMode::getCurrentInstance()->
				getPlayerCharacter()->sprite.getPosition();
		speaker->lookAt(playerPos.x, playerPos.y);
//	}
	currentDialogue->setSpeakerName(speaker->getName());
	if (speaker->getHasPortrait()) {
		currentDialogue->setPortraitFile(speaker->getPortraitFile());
	}
	dialogueWindow.setString(currentDialogue->getLineText(currentLine));
}

void DialogueManager::processDialogueEvents() {
	// Execute any scripted actions
	// TODO implement this
	// Handle choice events
	// TODO implement this
	// Find next line if there is one.
	int nextLine = currentDialogue->getNextLine(currentLine);
	// if this dialogue had a choice event, there should be different lines
	// depending on the choice
	// TODO implement choice events
	if (nextLine >= 0) {
		// If nextLine == -1, then the next Line is simply the next line sequentially
		// if it is not, then select the line that has been requested.
		// first check to see if this is a valid choice
		if (nextLine >= currentDialogue->getNumLines()) {
			std::cerr << "Requested invalid line.\n";
			nextLine = END_DIALOGUE;
		}
	} else if (nextLine == INCREMENT_LINE) {
		nextLine = currentLine + 1;
		if (nextLine >= currentDialogue->getNumLines()) {
			nextLine = END_DIALOGUE;
		}
	}
	if (dialogueWindow.finishedTyping()) {
		if (nextLine == END_DIALOGUE) {
			endDialogue();
		} else if (nextLine >= 0) {
			currentLine = nextLine;
			beginLine();
		} else {
			std::cerr << "Error: Invalid next dialogue line\n";
			endDialogue();
		}
	}
}

void DialogueManager::endDialogue() {
	if (currentDialogue == NULL) {
		std::cerr << "Error: Dialogue does not exist\n";
		return;
	}
	// TODO end of event processing when events are setup
	currentDialogue->incrementTimesSeen();
	//	currentOptions  = NULL;
	currentDialogue = NULL;
//	// Make sure that the speaker is facing in the original direction
//	OForce_Object::Object *obj = TownMode::getCurrentInstance()->getObjectManager()->
//				getObject(currentDialogue->getSpeaker(currentLine));
//	OForce_Object::Character *speaker = dynamic_cast<OForce_Object::Character *> (obj);
//	speaker->setDirection(oldDir);
	TownMode::getCurrentInstance()->setState(EXPLORE);
	TownMode::getCurrentInstance()->setCooldown(0.2f);
}

Dialogue *DialogueManager::getDialogue(int ID) {
	std::unordered_map<int, Dialogue *>::iterator it = dialogueMap.find(ID);
	if (it == dialogueMap.end()) {
		return NULL;
	} else {
		return it->second;
	}
}

void DialogueManager::hurry()
{
	dialogueWindow.hurry();
}

Dialogue::Dialogue(int id) : mId(id),
		currentLine(0),
		timesSeen(0)
{
	if (!font.loadFromFile("./data/Fonts/DejaVuSerif-Bold.ttf"))
		std::cout << "Cannot find font data.\n";
	if (!dialogueImage.loadFromFile("./data/characterTextBox.png"))
		std::cout << "Could not load character box.\n";
	dialogueImage.createMaskFromColor(sf::Color(19, 95, 181), 100);
	dialogueTexture.loadFromImage(dialogueImage);
	dialogueSprite.setTexture(dialogueTexture);
	dialogueText.setFont(font);
	dialogueText.setCharacterSize(18);
	sf::Vector2f viewCenter = view.getCenter();
	sf::Vector2f offset = view.getSize();
	offset.x /= 2.0;
	offset.x += 10.0;
	offset.y /= 2.0;
	offset.y -= 320.0;
	sf::Vector2f pos = viewCenter+offset;
	dialogueSprite.setPosition(pos);
	offset.x += 7.5;
	offset.y += 10.0;
	pos = viewCenter+offset;
	dialogueText.setPosition(pos);
}

void Dialogue::draw() {
	Window.draw(dialogueSprite);
	Window.draw(dialogueText);
}

void Dialogue::addLine(std::string text, int speakerID) {
//	dialogueText.setString(text);
	lines.push_back(text);
	speakers.push_back(speakerID);
	nextLineIDs.push_back(-1);
}

void Dialogue::addLine(std::string text, int speakerID, int nextLine) {
//	dialogueText.setString(text);
	lines.push_back(text);
	speakers.push_back(speakerID);
	nextLineIDs.push_back(nextLine);
}

}
